#!/usr/bin/python3
# -*- coding:utf-8 -*-
#python version: 3.6.7
'''
这个脚本是用来获取BaiduPCS-Go中需要用到的APPID的。
脚本运行后会循环尝试用某个APPID访问百度，如果ID可用则打印出来。
'''
#requests访问网页用的
import requests
#argv用来获取是否有传入参数
from sys import argv
#把要用的网址写到变量，中间的{}是留给后面format用的
url = 'http://pcs.baidu.com/rest/2.0/pcs/file?app_id={}&method=list&path=%2F'
#百度登陆的cookie放在文件中，不放在源码里格式好看一些，也不用每次重新登陆还要改源码
#这里打开cookie存放的文件
f_bduss = open('BDUSS.txt')
#准备好cookie变量，这里直接把读取文件内容写到一行里了
#每次read文本，python会自动加入一个'\n'，所以这里给替换掉
cookie = {"BDUSS":f_bduss.read().replace('\n','')}
#文件用完就关闭，防止意外终止
f_bduss.close()
#这个ua好像加不加都可以的，不过还是顺手加上吧
headers = {'user-agent': 'netdisk;8.3.1;android-android'}
#这个变量是用来存放读取网页期间所有出现的异常用的
#主要用途是在脚本结束后检查有没有除了被限制访问之外的异常信息
error_m = ""
#默认的rt方式打开文件在文件不存在时会报异常，所以要上一个try
try:
#打开存放扫到ID的文件
    f_pcsids = open('pcsids.txt')
#读出所有已经得到的ID
    pcsid_lines = f_pcsids.readlines()
#关闭文件
    f_pcsids.close()
#报文件不存在异常时的处理
except FileNotFoundError:
#给变量赋值为空list
    pcsid_lines = []
#如果说得出来的行数不小于2则代表该文件很可能是空文件
if len(pcsid_lines) < 2:
#这里重新给这个文件写2行，因为文件里如果只有一行文本的话python会出现0行
#先给变量一个新值
    pcsid_lines = ["#Don't del this line!\n"]*2
#以写入方式打开文件
    f_pcsids = open('pcsids.txt', 'w+')
#把变量写到文本文件中
    f_pcsids.writelines(pcsid_lines)
#关闭文件
    f_pcsids.close()
#这里先看一下有没有传入参数
#这里直接用try来看有没有参数和是否正确了
try:
#尝试把参数转成整数赋值给start_id
    start_id = int(argv[1])
#上一句中如果没有传入参数，会报IndexError，传入的不是数字会报ValueError
except(IndexError, ValueError):
#不管是没有参数还是参数非数字，都使用默认的方式来定义初始ID
#如果文本只有两行，则代表文件中没有存放任何ID
    if len(pcsid_lines) == 2:
#没存ID的，就直接从100000开始
        start_id = 100000
#前面小于2和等于2都已经处理了，到这个否则这里肯定会是一个大于2的数
    else:
#这个脚本会把最新得到的ID写在第一行，所以这里只用读第一个来做起始ID
        start_id = int(pcsid_lines[0].replace('\n',''))
#当前ID也赋值为起始ID
current_id = start_id
#用一个变量来存放当被拒绝访问时的异常文本，后面用到
con_e = "ConnectionError(ProtocolError('Connection aborted.', \
ConnectionResetError(104, 'Connection reset by peer')),)"
#再加一个变量用来记录拒绝访问的ID有哪些
con_en = []
#死循环访问ID，直到最后搜索到ID为止
while True:
#当前ID直接先+1,因为如果是文件中读到的ID，是验证过有效的
    current_id = current_id + 1
#打印出当前已经扫到哪个ID了，这里让最后不输出换行，留给后面
    print(current_id, end='')
#这个循环是尝试访问网址
    while True:
#写个try，脚本报异常也不会中止
        try:
#访问网址，取出网页源代码
            html = requests.get(url.format(current_id), headers = headers,
            cookies = cookie).content
#如果代码中出现error_code，则代表该ID无效
            if b'error_code' in html:
#代码无效就输出一个空文件，让前面输出的ID换行
                print('')
#否则代码显示ID有效
            else:
#代码有效就写到list中
                pcsid_lines.insert(0, str(current_id) + '\n')
#如果有效的ID已经大于两个了，那么空文件时写的占位用的文本就不需要了
                while len(pcsid_lines) > 2 and \
                pcsid_lines[-1] =="#Don't del this line!\n":
                    pcsid_lines.pop(-1)
#打开保存ID的文件，准备写入扫到的内容
                f_pcsids = open('pcsids.txt','w')
#写入扫到的ID
                f_pcsids.writelines(pcsid_lines)
#关闭文件
                f_pcsids.close()
#代码有效时，输出一个OK来提示用户
                print('\tok')
#不管有效无效，访问成功就可以跳出尝试访问的循环了
            break
#以下是如果出现异常的处理，这里主要是记录
        except Exception as e:
#变量记录一下当前出现的异常是啥
            error_n = repr(e)
#如果出的异常是拒绝访问
            if error_n == con_e:
#把出异常的ID记录下来，最后直接输出，免得最终输出异常信息时满满一屏重复内容
                con_en.append(current_id)
#当异常不是拒绝访问的时候，记录下异常的内容，最后输出出来好查错
            else:
#把异常信息和出现异常的ID写到变量中
                error_m = error_m + repr(e)+":"+str(current_id) + "\n"
#先确定得到的ID列表长度大于2，因为前两个不是ID
    if len(pcsid_lines) > 2:
#如果最新的有效ID大于起始ID，就是扫描到新的有效ID了
        if int(pcsid_lines[0].replace('\n','')) > start_id:
#扫描到了有效ID，可以跳出循环让脚本结束了
            break
#先判断一下有没有被拒绝访问的
if len(con_en) > 0:
#有异常就先打印一条分割线
    print("-" * 80)
#有的话，就打印到屏幕上
    print('Connection Error ID:' + str(con_en)[1:-1])
#判断一下有没有记录到其它异常的
if len(error_m) > 0:
#有异常就先打印一条分割线
    print("-" * 80)
#有的话输出所有记录下来的异常信息
    print(error_m)
